package wang.unclecat.textfieldhelper;

import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.ComponentParent;
import ohos.agp.utils.Rect;
import ohos.agp.window.service.Window;
import ohos.agp.window.service.WindowManager;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.eventhandler.InnerEvent;
import ohos.global.configuration.DeviceCapability;

/**
 * TextField工具类：自动上移TextField。监听软键盘显示、隐藏。
 */
public class TextFieldHelper {

    public TextFieldHelper(ITFHAdapter adapter) {
        this.adapter = adapter;
    }

    /**
     * 监听软键盘显示或隐藏
     */
    public interface SoftInputMonitor {
        void onSoftInputVisible(boolean isVisible);
    }

    public static final String TAG = TextFieldHelper.class.getSimpleName();
    private SoftInputMonitor softInputMonitor = null;
    private int maxDecorHeight;
    private int preDecorHeight;
    private ComponentContainer rootLayout;
    private Component preFocusComponent;
    private final ITFHAdapter adapter;

    private EventHandler eventHandler = new EventHandler(EventRunner.getMainEventRunner()) {
        private Rect decorRect = new Rect();

        @Override
        protected void processEvent(InnerEvent event) {
            super.processEvent(event);
            LogUtil.debug(TAG, String.format("processEvent() called  maxDecorHeight = %s", maxDecorHeight));

            int decorHeight = getDecorHeight(decorRect);
            if (decorHeight == 0) {
                return;
            }

            Component focusView = rootLayout.findFocus();
            if (preDecorHeight == decorHeight && focusView == preFocusComponent) {
                return;
            }
            preFocusComponent = focusView;
            preDecorHeight = decorHeight;

            if (focusView != null) {
                int moveY = adapter.calculateMoveY(decorRect, focusView);
                boolean isKBShow = maxDecorHeight - decorRect.getHeight() > 100;
                adapter.move(moveY, isKBShow);
                LogUtil.debug(TAG, String.format("processEvent() called decorHeight = %d, maxDecorHeight = %d, moveY = %d", decorHeight, maxDecorHeight, moveY));
                LogUtil.info(TAG, String.format("------------ SoftInput show : %s", isKBShow));
                if (softInputMonitor != null) {
                    softInputMonitor.onSoftInputVisible(isKBShow);
                }
            }
        }
    };

    /**
     * 监听布局变化，并将焦点输入框显示在软键盘的上方
     *
     * @param window 用来设置 INPUT_ADJUST_PAN
     * @param uiContent 包含TextField的布局，一般传入根布局
     * @param isMonitorParent 是否监听父容器（如以addComponent方式到Ability的decorView中显示的dialog，这里传入true）
     * @param delayTime delay一定时间后再监听(实测结果:dialog一般需要至少delay 150毫秒)
     */
    public void monitorLayoutRefreshed(Window window, ComponentContainer uiContent, boolean isMonitorParent, long delayTime) {
        if (delayTime > 0) {
            eventHandler.postTask(() -> monitorLayoutRefreshed(window, uiContent, isMonitorParent), delayTime);
        } else {
            monitorLayoutRefreshed(window, uiContent, isMonitorParent);
        }
    }

    /**
     * 监听布局变化，并将焦点输入框显示在软键盘的上方
     */
    public void monitorLayoutRefreshed(Window window, ComponentContainer uiContent, long delayTime) {
        if (delayTime > 0) {
            eventHandler.postTask(() -> monitorLayoutRefreshed(window, uiContent), delayTime);
        } else {
            monitorLayoutRefreshed(window, uiContent);
        }
    }

    /**
     * 监听布局变化，并将焦点输入框显示在软键盘的上方
     */
    public void monitorLayoutRefreshed(Window window, ComponentContainer uiContent) {
        monitorLayoutRefreshed(window, uiContent, false);
    }

    /**
     * 监听布局变化，并将焦点输入框显示在软键盘的上方
     */
    public void monitorLayoutRefreshed(Window window, ComponentContainer uiContent, boolean isMonitorParent) {
        window.setInputPanelDisplayType(WindowManager.LayoutConfig.INPUT_ADJUST_PAN);
        rootLayout = adapter.findRootLayout(uiContent);
        if (maxDecorHeight == 0) {
            DeviceCapability deviceCapability = uiContent.getResourceManager().getDeviceCapability();
            maxDecorHeight = deviceCapability.height * deviceCapability.screenDensity / 160;
        }

        //监听DecorView变化
        if (isMonitorParent) {
            findParentRootForMonitor(uiContent).setLayoutRefreshedListener(component -> checkSoftInput());
        } else {
            rootLayout.setLayoutRefreshedListener(component -> checkSoftInput());
        }
    }

    //需要根组件来监听
    private Component findParentRootForMonitor(ComponentContainer uiContent) {
        ComponentParent parent = uiContent;
        while (parent.getComponentParent() != null) {
            parent = parent.getComponentParent();
        }
        return (Component) parent;
    }

    /**
     * 监听软键盘显示或隐藏
     */
    public void setSoftInputMonitor(SoftInputMonitor monitor) {
        this.softInputMonitor = monitor;
    }

    private int getDecorHeight(Rect decorRect) {
        if (rootLayout != null) {
            //包括标题栏，但不包括状态栏。默认 大小 (0,129,1080,2340),top=129即状态栏 , height=2211。 同android的decorView
            rootLayout.getWindowVisibleRect(decorRect);
            return decorRect.getHeight();
        }
        return 0;
    }


    /**
     * 将焦点输入框显示在软键盘的上方
     */
    //需要delay后再移动(密码输入会有键盘切换，需要一点时间界面才会变化)
    private void checkSoftInput() {
        LogUtil.debug(TAG, "checkSoftInput() called");
        eventHandler.removeAllEvent();
        InnerEvent event = InnerEvent.get();
        eventHandler.sendEvent(event, 200);
    }
}
